#include "DefferRenderAttachments.h"
#include "Render/VulkanContext.h"
#include "Render/Texture/GPURenderTarget.h"

#include "Render/VulkanRecycleObjects.h"

CDefferRenderAttachments::CDefferRenderAttachments(vk::Extent2D InViewportSize)
{
    ViewportSize=InViewportSize;

    AlbedoAndAO = std::make_shared<CGPURenderTarget>();
    AlbedoAndAO->Initialize(vk::Extent3D(InViewportSize.width, InViewportSize.height, 1), 
        vk::Format::eR16G16B16A16Sfloat,
        vk::ImageUsageFlagBits::eColorAttachment |vk::ImageUsageFlagBits::eInputAttachment  | vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferSrc
    );

    NormalAndRoughness = std::make_shared<CGPURenderTarget>();
    NormalAndRoughness->Initialize(vk::Extent3D(InViewportSize.width, InViewportSize.height, 1), 
        vk::Format::eR16G16B16A16Sfloat,
        vk::ImageUsageFlagBits::eColorAttachment |vk::ImageUsageFlagBits::eInputAttachment| vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferSrc
    );
    PositionAndMetalness = std::make_shared<CGPURenderTarget>();
    PositionAndMetalness->Initialize(vk::Extent3D(InViewportSize.width, InViewportSize.height, 1), 
        vk::Format::eR16G16B16A16Sfloat,
        vk::ImageUsageFlagBits::eColorAttachment |vk::ImageUsageFlagBits::eInputAttachment| vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferSrc
    );

    Misc = std::make_shared<CGPURenderTarget>();
    Misc->Initialize(vk::Extent3D(InViewportSize.width, InViewportSize.height, 1), 
        vk::Format::eR16G16B16A16Sfloat,
        vk::ImageUsageFlagBits::eColorAttachment |vk::ImageUsageFlagBits::eInputAttachment| vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferSrc
    );


    ShadeOutput= std::make_shared<CGPURenderTarget>();
    ShadeOutput->Initialize(vk::Extent3D(InViewportSize.width, InViewportSize.height, 1), 
        vk::Format::eR16G16B16A16Sfloat,
        vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferSrc
    );

    Depth = std::make_shared<CGPURenderTarget>();
    Depth->Initialize(vk::Extent3D(InViewportSize.width, InViewportSize.height, 1), 
        vk::Format::eD32Sfloat,
        vk::ImageUsageFlagBits::eDepthStencilAttachment | vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferSrc
    );

    
    //create framebuffer
    std::vector<vk::ImageView> Attachments = {
        AlbedoAndAO->GetImageView(),
        NormalAndRoughness->GetImageView(),
        PositionAndMetalness->GetImageView(),
        Misc->GetImageView(),
        ShadeOutput->GetImageView(),
        Depth->GetImageView(),
    };



    vk::FramebufferCreateInfo FrameBufferInfo = vk::FramebufferCreateInfo()
        .setRenderPass(CVulkanContext::Get()->GetSceneGlobal()->SceneRenderPass)
        .setAttachmentCount(Attachments.size())
        .setPAttachments(Attachments.data())
        .setWidth(InViewportSize.width)
        .setHeight(InViewportSize.height)
        .setLayers(1);

    FrameBuffer = CVulkanContext::Get()->GetDevice().createFramebuffer(FrameBufferInfo);

    ClearValues=
        {
            vk::ClearColorValue(std::array<float,4>{0.0f,0.0f,0.0f,1.0f}), //Albedo
            vk::ClearColorValue(std::array<float,4>{0.0f,0.0f,0.0f,1.0f}), //Normal
            vk::ClearColorValue(std::array<float,4>{0.0f,0.0f,0.0f,1.0f}), //Position
            vk::ClearColorValue(std::array<float,4>{0.0f,0.0f,0.0f,1.0f}), //Misc
            vk::ClearColorValue(std::array<float,4>{0.0f,0.0f,0.0f,1.0f}), //ShadeOutput
            vk::ClearDepthStencilValue(1.0f, 0.0f), //Depth

        };




}


void CDefferRenderAttachments::PrepareSelfRecord()
{
    SVulkanDescriptorPoolSize PoolSize;
    PoolSize.SetNum=1;
    PoolSize+=CVulkanContext::Get()->GetSceneGlobal()->DefferShadingDescriptorSetLayout.DescriptorNums;
    CVulkanContext::Get()->GetAutoResetDescriptorPool()->GenerallPool.PoolSize+=PoolSize;
}

void CDefferRenderAttachments::CreateDescriptorSet()
{
    //create descriptor set
    {

        SVulkanDescriptorLayout DescriptorLayout=
            CVulkanContext::Get()->GetSceneGlobal()->DefferShadingDescriptorSetLayout;

        vk::DescriptorSetAllocateInfo DescriptorSetAllocateInfo = vk::DescriptorSetAllocateInfo()
            .setDescriptorPool(CVulkanContext::Get()->GetAutoResetDescriptorPool()->GenerallPool.Pool)
            .setDescriptorSetCount(1)
            .setPSetLayouts(&DescriptorLayout.Layout);

        DescriptorSet =CVulkanContext::Get()->GetDevice().allocateDescriptorSets(DescriptorSetAllocateInfo)[0];


        //update descriptor set
        TVector<vk::DescriptorImageInfo> DescriptorImageInfos=
        {
            vk::DescriptorImageInfo()
            .setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
            .setImageView(AlbedoAndAO->GetImageView())
            ,

            vk::DescriptorImageInfo()
            .setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
            .setImageView(NormalAndRoughness->GetImageView())
            ,

            vk::DescriptorImageInfo()
            .setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
            .setImageView(PositionAndMetalness->GetImageView())
            ,

            vk::DescriptorImageInfo()
            .setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
            .setImageView(Misc->GetImageView())
        };

        TVector<vk::WriteDescriptorSet> WriteDescriptorSets=
        {
            vk::WriteDescriptorSet()
                .setDstSet(DescriptorSet)
                .setDstBinding(0)
                .setDescriptorType(vk::DescriptorType::eInputAttachment)
                .setDescriptorCount(1)
                .setImageInfo(DescriptorImageInfos[0])
            ,
            vk::WriteDescriptorSet()
                .setDstSet(DescriptorSet)
                .setDstBinding(1)
                .setDescriptorType(vk::DescriptorType::eInputAttachment)
                .setDescriptorCount(1)
                .setImageInfo(DescriptorImageInfos[1])
            ,
            vk::WriteDescriptorSet()
                .setDstSet(DescriptorSet)
                .setDstBinding(2)
                .setDescriptorType(vk::DescriptorType::eInputAttachment)
                .setDescriptorCount(1)
                .setImageInfo(DescriptorImageInfos[2])
            ,
            vk::WriteDescriptorSet()
                .setDstSet(DescriptorSet)
                .setDstBinding(3)
                .setDescriptorType(vk::DescriptorType::eInputAttachment)
                .setDescriptorCount(1)
                .setImageInfo(DescriptorImageInfos[3])
            
        };

        CVulkanContext::Get()->GetDevice().updateDescriptorSets(WriteDescriptorSets, nullptr);
    }
}

CDefferRenderAttachments::~CDefferRenderAttachments()
{
    CVulkanContext::Get()->GetRecycleObjects()->Framebuffers.Add(FrameBuffer);
}
